﻿using System;
using System.Linq;
using System.Web.Mvc;

using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.Common.Locator;

using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.Domain.Special;

namespace Fuse8.ContentManagementFramework.Web.MvcPowered
{
    public static class CmsPagePropertyHtmlHelperExtension
    {        
        /// <summary>
        /// Renders value from special (MetaFieldName is 'cmsPageProperty') page meta field by specified key.
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="property">Property name</param>        
        /// <returns></returns>
        public static KeyValueCmsPageProperty PageProperty(this HtmlHelper htmlHelper, string property)
        {
            return PageProperty(htmlHelper, property, 0, false, string.Empty);
        }

        /// <summary>
        /// Renders value from special (MetaFieldName is 'cmsPageProperty') page meta field by specified key.
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="property">Property name</param>
        /// <param name="level">Max level for page hierarchy to retrieve property</param>        
        /// <returns></returns>
        public static KeyValueCmsPageProperty PageProperty(this HtmlHelper htmlHelper, string property, int level)
        {
            return PageProperty(htmlHelper, property, level, false, string.Empty);
        }

        /// <summary>
        /// Renders value from special (MetaFieldName is 'cmsPageProperty') page meta field by specified key.
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="property">Property name</param>
        /// <param name="inhereted">Idicates whether it is necessary to use hierarchy to retrieve property</param>        
        /// <returns></returns>
        public static KeyValueCmsPageProperty PageProperty(this HtmlHelper htmlHelper, string property, bool inhereted)
        {
            return PageProperty(htmlHelper, property, 0, inhereted, string.Empty);
        }

        /// <summary>
        /// Renders value from special (MetaFieldName is 'cmsPageProperty') page meta field by specified key.
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="property">Property name</param>
        /// <param name="level">Max level for page hierarchy to retrieve property</param>
        /// <param name="inhereted">Idicates whether it is necessary to use hierarchy to retrieve property</param>        
        /// <returns></returns>
        public static KeyValueCmsPageProperty PageProperty(this HtmlHelper htmlHelper, string property, int level, bool inhereted)
        {
            return PageProperty(htmlHelper, property, level, inhereted, string.Empty);
        }

        /// <summary>
        /// Renders value from special (MetaFieldName is 'cmsPageProperty') page meta field by specified key.
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="property">Property name</param>
        /// <param name="level">Max level for page hierarchy to retrieve property</param>
        /// <param name="inhereted">Idicates whether it is necessary to use hierarchy to retrieve property</param>
        /// <param name="formatString">Format string to present property value.</param>        
        /// <returns></returns>
        public static KeyValueCmsPageProperty PageProperty(this HtmlHelper htmlHelper, string property, int level, bool inhereted, string formatString)
        {
            return new KeyValueCmsPageProperty(htmlHelper, property, level, inhereted, formatString);
        }

        /// <summary>
        /// Renders page meta field by specified name.
        /// </summary>
        /// <typeparam name="TProperty">Meta Field Type</typeparam>
        /// <param name="htmlHelper"></param>
        /// <param name="propertyName">Meta Field name</param>
        /// <param name="level">Max level for page hierarchy to retrieve property</param>
        /// <param name="inhereted">Idicates whether it is necessary to use hierarchy to retrieve property</param>        
        /// <remarks>If Template is not specified it renders result of method ToString() of TProperty object</remarks>
        /// <returns></returns>
        public static CmsPageProperty<TProperty> PageProperty<TProperty>(this HtmlHelper htmlHelper, string propertyName, int level = 0, bool inhereted = false)
        {
            return new CmsPageProperty<TProperty>(htmlHelper, propertyName, level, inhereted, String.Empty);
        }
    }

    public class KeyValueCmsPageProperty : CmsPageProperty<CmsPagePropertyItem>
    {
        public KeyValueCmsPageProperty(HtmlHelper htmlHelper, string property, int level, bool inhereted, string formatString) : base(htmlHelper, property, level, inhereted, formatString)
        {
        }

        protected override CmsPagePropertyItem InternalGetProperty(CmsPage workingPage)
        {
            CmsPagePropertyItem result = null;
            var data = workingPage.GetMetaValue<CmsPagePropertiesContainer>(CmsPage.PagePropertyKey);
            if (data != null)
            {
                result =
                    data.Properties.FirstOrDefault(
                        p => p.PropertyName.Equals(Property, StringComparison.OrdinalIgnoreCase));
            }

            return result;
        }

        protected override string ConvertToString(CmsPagePropertyItem workingValue)
        {
            return workingValue.PropertyValue;
        }
    }

    public class CmsPageProperty<TProperty> : CmsMvcBaseComponent<CmsPageProperty<TProperty>, TProperty>
    {
        #region Fields

        private CmsPage _currentPage = DependencyServiceLocator.Current.GetInstance<ICmsContext>().ContextPage;

        #endregion

        #region Property

        public int MaxLevelUp { get; set; }

        public bool Inhereted { get; set; }

        public string Property { get; set; }

        public string FormatString { get; set; }

        protected int CurrentPageLevel
        {
            get
            {
                return _currentPage.PageLevel;
            }
        }

        protected override TProperty Value
        {
            get
            {
                var value = base.Value;

                if (object.Equals(value, default(TProperty)))
                {
                    value = GetPageProperty(_currentPage);

                    base.Value = value;
                }

                return value;
            }
        }

        #endregion

        #region Constructor

        public CmsPageProperty(HtmlHelper htmlHelper, string property, int level, bool inhereted, string formatString)
            : base(htmlHelper)
        {
            Property = property;

            MaxLevelUp = level;

            Inhereted = inhereted;

            FormatString = formatString;

            Component = this;
        }

        #endregion

        #region Methods

        protected override string RenderComponent()
        {
            string result = null;

            if (InlineTemplate != null)
            {
                result = base.RenderComponent();
            }
            else if (!string.IsNullOrWhiteSpace(Property))
            {
                var workingValue = Value;
                if (workingValue != null)
                {
                    result = ConvertToString(workingValue);

                    if (!string.IsNullOrWhiteSpace(result) && !string.IsNullOrWhiteSpace(FormatString))
                    {
                        result = string.Format(FormatString, result);
                    }
                }
            }

            return result ?? string.Empty;
        }

        protected virtual string ConvertToString(TProperty workingValue)
        {
            return workingValue.ToString();
        }

        protected TProperty GetPageProperty(CmsPage workingPage)
        {
            TProperty result = default(TProperty);

            if (workingPage != null)
            {
                var data = InternalGetProperty(workingPage);
                                
                if (!object.Equals(data, default(TProperty)))
                {
                    result = data;
                }
                else if(Inhereted)
                {
                    result = GetPageProperty(GetNextWorkingPage(workingPage));
                }
            }

            return result;
        }

        protected virtual TProperty InternalGetProperty(CmsPage workingPage)
        {
            return workingPage.GetMetaValue<TProperty>(Property);
        }

        protected virtual CmsPage GetNextWorkingPage(CmsPage workingPage)
        {
            CmsPage result = null;

            if (workingPage != null)
            {
                if (MaxLevelUp > 0)
                {
                    result = workingPage.ParentPage;
                    if (result != null)
                    {
                        if (CurrentPageLevel - result.PageLevel <= MaxLevelUp)
                        {
                            result = null;
                        }
                    }
                }
                else
                {
                    result = workingPage.ParentPage;
                }
            }

            return result;
        }

        #endregion
    }
}
